﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Batbaille.TAC;
//using Batbaille.SwapOffice;

namespace TestForeignVocabulary
{
	// Normal :		WordMotherTongue	-> WordTranslated
	// Reverse :	WordTranslated		-> WordMotherTongue
	public enum TransDirection { Normal, Reverse }

	public class TranslationExercise
	{
	#region Attributs & Properties

		private List<Translation> _listTransImport;
		public List<Translation> ListTransImport
		{
			get { return _listTransImport; }
			private set { _listTransImport = value; }
		}

		private List<Translation> _listTransDico;
		public List<Translation> ListTransDico
		{
			get { return _listTransDico; }
			private set { _listTransDico = value; }
		}

		private List<Translation> _listTransExercice;
		public List<Translation> ListTransExercice
		{
			get { return _listTransExercice; }
			private set { _listTransExercice = value; }
		}

		private TransDirection _eTheTransDirection;
		public TransDirection TheTransDirection
		{
			get { return _eTheTransDirection; }
			set { _eTheTransDirection = value; }
		}

		private int _nPercentDifficulty;
		public int PercentDifficulty
		{
			get { return _nPercentDifficulty; }
			set
			{
				if (_nPercentDifficulty < 0)
					_nPercentDifficulty = 0;
				else
				{
					_nPercentDifficulty = value;
				}
			}
		}

		private SpreadSheet _oSpreadSheetInfo;	
		public SpreadSheet SpreadSheetInfo
		{
			get { return _oSpreadSheetInfo; }
			set { _oSpreadSheetInfo = value; }
		}

		public int NbTranslationDico
		{
			get { return _listTransDico.Count; }
		}

		public int NbTranslationImport
		{
			get { return _listTransImport.Count; }
		}
				
		public int NbTranslationExercice
		{
			get { return _listTransExercice.Count; }
		}

		public int Score
		{
			get
			{
				int nScore = 0;						
				foreach (Translation oTrad in ListTransExercice)
				{
					if (oTrad == null) continue;
					nScore += oTrad.Score;					
				}				
				return nScore;
			}
		}

		public int NbNotTranslatedOfExercice
		{
			get
			{
				int nNbNotTranslated = 0;
				foreach (Translation oTrad in ListTransExercice)
				{
					if (oTrad == null) continue;
					if( oTrad.IsTranslatedNever )
						nNbNotTranslated++;
				}
				return nNbNotTranslated;
			}
		}

		public int NbTranslatedOfExercice
		{
			get
			{
				int nNbTranslated = 0;
				foreach (Translation oTrad in ListTransExercice)
				{
					if (oTrad == null) continue;
					if (oTrad.IsTranslatedAtLeastOnce)
						nNbTranslated++;
				}
				return nNbTranslated;
			}
		}

	#endregion
	#region Constructors

		public TranslationExercise()
        {
			_listTransDico			= new List<Translation>();
			_listTransExercice		= new List<Translation>();
			_listTransImport		= new List<Translation>();

			_eTheTransDirection = TransDirection.Normal;
			
			Batbaille.TAC.SerializationBinary.DefaultFilePath = Environment.CurrentDirectory + "\\Dico.bat";			
        }

    #endregion
	#region Methods - Tool

		private Translation FindTranslationInDico(string strWordFromTrans, string strWordToTrans)
		{			
			return FindTranslationInListTrans(ListTransDico, strWordFromTrans, strWordToTrans);
		}

		private Translation FindTranslationInImport(string strWordFromTrans, string strWordToTrans)
		{			
			return FindTranslationInListTrans(ListTransImport, strWordFromTrans, strWordToTrans);
		}

		private static Translation FindTranslationInListTrans(List<Translation> ListTrans, string strWordFromTrans, string strWordToTrans)
		{
			Translation oTrad = ListTrans.Find(delegate(Translation match)
            { 
                bool bResult = false;
				if (match.WordFromTrans == strWordFromTrans && match.WordToTrans == strWordToTrans)
                    bResult = true;               
                return bResult;
            });
            return oTrad;
		}

		public Translation FindFromTranslateInExercise(string strWordFromTrans)
		{
			Translation oTrad = ListTransDico.Find(delegate(Translation match)
			{
				bool bResult = false;
				if (match.WordFromTrans == strWordFromTrans)
					bResult = true;
				return bResult;
			});
			return oTrad;
		} 

		private bool IsPresentTranslate( string strWordFromTrans, string strWordToTrans )
		{
			if( FindTranslationInDico(strWordFromTrans, strWordToTrans) != null )
				return true;

			return false;
		}

	#endregion
	#region Methods - Operation

		public Translation AddTranslationInDico(string strWordFromTrans, string strWordToTrans)
		{
			if( !IsPresentTranslate(strWordFromTrans, strWordToTrans) )
			{
				Translation oTrad = new Translation(this, strWordFromTrans, strWordToTrans);
				ListTransDico.Add(oTrad);
				return oTrad;
			}

			return null;
		}		

		public void MixList(bool bInitListtransExercice = false, int nNbTranslation = 0)
		{
			List<Translation> listTempSrc;
            
			if (ListTransImport.Count == 0)
				listTempSrc = new List<Translation>(ListTransDico);
			else
				listTempSrc = new List<Translation>(ListTransImport);          

			if( listTempSrc.Count <= 0 )
				return;

			List<Translation> listTempSrcBis = listTempSrc;
			listTempSrc = new List<Translation>();
			foreach( Translation oTrans in listTempSrcBis )
			{
				if( oTrans.PercentMistake >= PercentDifficulty )
					listTempSrc.Add( oTrans );
			}

			if( nNbTranslation <= 0 || nNbTranslation > listTempSrc.Count )
			{
				nNbTranslation = listTempSrc.Count;
			}			

			ListTransExercice = new List<Translation>();
						
			Random oRamdom = new Random();
			Translation oTrad;
            while (ListTransExercice.Count < nNbTranslation)
			{
				int nIndex	= oRamdom.Next(listTempSrc.Count);
				oTrad		= listTempSrc[nIndex];
				ListTransExercice.Add(oTrad);
				listTempSrc.RemoveAt(nIndex);
			}   
		}

		public void InitScore()
		{
			for (int i = 0; i < this.ListTransExercice.Count; i++)
			{
				Translation oTrad = ListTransExercice[i];
				if (oTrad == null) continue;

				oTrad.InitScore();
			}
		}

		public void InitTranslated()
		{
			for (int i = 0; i < this.ListTransExercice.Count; i++)
			{
				Translation oTrad = ListTransExercice[i];
				if (oTrad == null) continue;

				oTrad.InitTranslated();
			}
		}

		public bool Verification(string strWordToTranslate, string strProposition )
		{

			Translation oTrans = FindFromTranslateInExercise(strWordToTranslate);
			if( oTrans == null )
				return false;

			return oTrans.Verification( strProposition );
		}		

	#endregion
	#region Methods - Data
		
		public void Import(string strFileName)
		{
			ListTransImport.Clear();

			SpreadSheetInfo = new SpreadSheet(strFileName, false);
			if (SpreadSheetInfo == null)
				return;

			SpreadSheetInfo.ReadAll();

			for (int f = 0; f < SpreadSheetInfo.CountSheet; f++)
			{
				Sheet oSheet = SpreadSheetInfo[f];
				if( oSheet == null )
					continue;

				for (int l = 0; l < oSheet.CountLine; l++)
				{
					List<string> oLine = oSheet[l];
					if (oLine == null) continue;
					if (oSheet.CountColumn < 2) continue;
					if (oLine.Count < 2) continue;

					string strNomColone1 = oLine[0].ToString();;
					bool bIsFirstColumnFrench = false;
					if (strNomColone1 == "FR")
						bIsFirstColumnFrench = true;

					string strFrench;
					string strEnglish;
					if (bIsFirstColumnFrench)
					{
						strFrench = oLine[0];
						strEnglish = oLine[1];
					}
					else
					{
						strFrench = oLine[1];
						strEnglish = oLine[0];
					}

					Translation oTrans = FindTranslationInDico(strFrench, strEnglish);
					if( oTrans == null )
						oTrans = AddTranslationInDico(strFrench, strEnglish);

					if( oTrans != null )
						ListTransImport.Add(oTrans);
				}
			}			
		}

		public void Export(string strFileName)
		{
			if (SpreadSheetInfo == null)
				return;

			SpreadSheetInfo.FilePath = strFileName;

			Sheet oSheet = SpreadSheetInfo[0];
			if (oSheet == null)
				return;

			/*
			if(oSheet.CountColumn == 2 ) 
			{				
				string strHead2 = "SUCCESS";
				string strHead3 = "MISTAKE";				
				oSheet.ListHeader.Add(strHead2);
				oSheet.ListHeader.Add(strHead3);			
			}
			else if(oSheet.CountColumn > 2 ) 
			{
			}
			 * */
			
			oSheet.ClearLine();
			foreach(Translation oTrans in ListTransDico )
			{
				string strWM = oTrans.WordMotherTongue;
				string strWT = oTrans.WordTranslated;
				string strNS = oTrans.NbSuccess.ToString();
				string strNM = oTrans.NbMistake.ToString();

				List<string> ListValue = new List<string>();
				ListValue.Add(strWT);
				ListValue.Add(strWM);
				ListValue.Add(strNS);
				ListValue.Add(strNM);

				oSheet.ListLine.Add(ListValue);
			}

			List<int> listKey = new List<int>{ 0, 1};
			oSheet.ListIndKey = listKey;

			SpreadSheetInfo.WriteSheet(0);
		}
		
        public void SaveBinary()
        {			
			SerializationBinary.Save<List<Translation>>(ListTransDico);
        }

        public bool LoadBinary()
        {           			
			List<Translation> listDicoTemp = SerializationBinary.Load<List<Translation>>();

            if (listDicoTemp != null && listDicoTemp.Count > 0)
            {
				foreach(Translation otrans in listDicoTemp)
				{
					otrans.ExerciseDad = this;
				}
				

				ListTransDico = listDicoTemp;
                return true;
            }
            return false;
        }

        public void ClearBinary()
        {			
			ListTransDico.Clear();
			ListTransImport.Clear();
			ListTransExercice.Clear();
			SerializationBinary.Clear<List<Translation>>();
        }	   
	
	#endregion
	}

	[Serializable]
	public class Translation
	{
	#region Attributs & Properties

		[NonSerialized]
		private TranslationExercise _oExerciseDad;
		public TranslationExercise ExerciseDad
		{
			get { return _oExerciseDad; }
			set { _oExerciseDad = value; }
		}		

		/*
		public static TransDirection TheTransDirection
		{
			get { return Translation._enTheTransDirection; }
			set { Translation._enTheTransDirection = value; }
		}
		 */
		
		private string	_strWordMotherTongue;
		public string WordMotherTongue
		{
		  get { return _strWordMotherTongue; }
		  set { _strWordMotherTongue = value; }
		}
		
		private string _strWordTranslated;
		public string WordTranslated
		{
		  get { return _strWordTranslated; }
		  set { _strWordTranslated = value; }
		}

		public string WordFromTrans
		{
			get
			{
				if (ExerciseDad.TheTransDirection == TransDirection.Reverse)
					return _strWordTranslated;

				return _strWordMotherTongue;
			}
		}

		public string WordToTrans
		{
			get 
			{
				if (_oExerciseDad.TheTransDirection == TransDirection.Normal)
					return _strWordTranslated;
				
				return _strWordMotherTongue;
			}
		}
				
		private int		_nNbSuccess;
		public int NbSuccess
		{
			  get { return _nNbSuccess; }
			  private set { _nNbSuccess = value; }
		}
				
		private int		_nNbMistake;
		public int NbMistake
		{
			get { return _nNbMistake; }
			private set { _nNbMistake = value; }
		}
				
		public int NbAttempt
		{
			get { return NbSuccess+NbMistake; }
		}

		private bool _bIsTranslatedAtLeastOnce;
		public bool IsTranslatedAtLeastOnce
		{
			get { return _bIsTranslatedAtLeastOnce; }
			private set { _bIsTranslatedAtLeastOnce = value; }
		}

		public bool IsTranslatedNever
		{
			get { return !IsTranslatedAtLeastOnce; }
		}

		public int Score
		{
			get { return NbSuccess - NbMistake; }
		}

		public int PercentMistake
		{
			get 
			{ 
				if( NbAttempt != 0 )
					return (NbMistake*100 / NbAttempt); 
				
				return 50;
			}
		}

		public int PercentSuccess
		{
			get
			{
				if (NbAttempt != 0)
					return (NbSuccess * 100 / NbAttempt);

				return 50;
			}
		}

	#endregion
	#region Constructors

		private Translation()
		{		
			NbSuccess = 0;
			NbMistake = 0;
			IsTranslatedAtLeastOnce = false;
		}

		public Translation(TranslationExercise oExercise, string strWordMotherTongue, string strWordTranslated):this()
		{
			ExerciseDad				= oExercise;
			this.WordMotherTongue	= strWordMotherTongue;
			this.WordTranslated		= strWordTranslated;			
		}

	#endregion	
	#region Methods - Tools

		private static string GetWordFormated(string strWord)
		{
			while (strWord.IndexOf('(') != -1)
			{
				int nIndex = strWord.IndexOf('(');
				int nIndex2 = strWord.IndexOf(')', nIndex);

				if (nIndex != -1 && nIndex2 != -1 && nIndex < nIndex2)
				{
					strWord = strWord.Remove(nIndex, nIndex2 - nIndex + 1);
				}
				else
				{
					strWord = strWord.Replace('(', ' ');
					strWord = strWord.Replace(')', ' ');
				}
			}

			strWord = strWord.Replace('-', ' ');
			strWord = strWord.Replace('!', ' ');
			strWord = strWord.Replace('?', ' ');
			strWord = strWord.Replace("…", "");
			strWord = strWord.Replace("...", "");
			strWord = strWord.Trim().ToLower();

			return strWord;
		}
				
	#endregion
	#region Methods - Operation

		public bool IsRight(string strProposition)
		{
			bool bRight = true;

			string[] resVerif = WordToTrans.Split(new char[] { '/' });
			string[] resPropo = strProposition.Split(new char[] { '/' });

			// Il faut autant de mots à gauche qu'à droite sépraré par des "/"
			if (resVerif.Length == resPropo.Length)
			{
				// on compare chaque mot entre "/" , tous les mots doivent correspondre
				for (int i = 0; i < resVerif.Length && bRight; i++)
				{
					bRight = false;

					string strResVerif = resVerif[i];
					string strResPropo = resPropo[i];

					// On regarde tous les mots potentiels entre ","
					string[] resVerifBis = strResVerif.Split(new char[] { ',' });
					if (resVerifBis.Length > 0)
					{
						for (int j = 0; j < resVerifBis.Length && !bRight; j++)
						{
							// Si l'un d'eux correspond, c'est bon 
							if (GetWordFormated(resVerifBis[j]) == GetWordFormated(strResPropo))
								bRight = true;
						}
					}
				}
			}
			else
				return false;

			return bRight;
		}	

		public bool Verification( string strProposition)
		{
			// Vérification et comptabilisation
			if (IsRight(strProposition))
			{
				NbSuccess++;
				IsTranslatedAtLeastOnce=true;
				return true;
			}

			NbMistake++;
			return false;
		}

		public void InitScore()
		{
			NbSuccess = 0;
			NbMistake = 0;
		}

		public void InitTranslated()
		{
			IsTranslatedAtLeastOnce = false;
		}
	
	#endregion
	}

}
